/***************************************************************************
 *   Copyright (C) 2005 by xihe   *
 *   xihels@163.com                                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "Login.h"
#include "QQClient.h"


int LoginPacket::putLoginHead(uint8_t* buf) const 
{ 
    uint8_t* cur = buf;
    // 初始密钥
    cur += writeBufData(cur, client.getIniKey(), QQ_KEY_LENGTH);
    return cur - buf;
}

int LoginPacket::putBody(uint8_t* buf) const
{
    uint8_t* cur = buf;

    // 头16个字节用md5处理的密码加密一个空字符串，这用来在服务器端校验密码
    int encryptlen = QQ_KEY_LENGTH;
    QQClient::encrypt(NULL, 0, cur, encryptlen, client.getPwkey());
    cur += QQ_KEY_LENGTH;

    // 36字节的固定内容
    cur += writeBufData(cur, LOGIN_16_51, sizeof (LOGIN_16_51));

    // 登录状态，隐身登录还是什么，1字节
    cur += writeBufB(cur, client.getLoginMode());

    // 16字节固定内容
    cur += writeBufData(cur, LOGIN_53_68, sizeof (LOGIN_53_68));

    // 登录令牌长度，1字节
    uint8_t tokenlen = static_cast<uint8_t>(client.getLoginToken().size());
    cur += writeBufB(cur, tokenlen);

    // 登录令牌
    cur += writeBufData(cur,
	    reinterpret_cast<const uint8_t*>((client.getLoginToken().c_str())),
	    client.getLoginToken().size());


    // 每次基本都是固定内容，未知含义
    cur += writeBufData(cur, LOGIN_SEGMENTS, sizeof (LOGIN_SEGMENTS));

    // 长度不足则全部填0直到符合登录包长度
    bzero(cur, buf + QQ_LOGIN_DATA_LENGTH - cur);

//    fprintf(stderr, "\n");
//    for (int i = 0; i < QQ_LOGIN_DATA_LENGTH; i++)
//	fprintf(stderr, "%02x ", buf[i]);
//    fprintf(stderr, "\n");

    return QQ_LOGIN_DATA_LENGTH;

}

//==================================================================================//

LoginReplyPacket::LoginReplyPacket(const uint8_t* buf, int len) :
    InPacket(buf, len)
{
    const uint8_t* cur = buf + QQ_HEADER_LENGTH_BASIC_FAMILY_IN;

    cur += readBufB(replyCode, cur);

    switch (replyCode) {
	case QQ_LOGIN_REPLY_OK:
	    // 001-016字节是session key
	    cur += writeBufData(sessionKey, cur, QQ_KEY_LENGTH);

	    // 017-020字节是用户QQ号
	    cur += 4;

	    // 021-024字节是服务器探测到的用户IP
	    cur += readBufDw(ip, cur);

	    // 025-026字节是服务器探测到的用户端口
	    cur += readBufW(port, cur);

	    // 027-030字节是服务器自己的IP
	    cur += readBufDw(serverIp, cur);

	    // 031-032字节是服务器的端口
	    cur += readBufW(serverPort, cur);

	    // 033-036字节是本次登陆时间，为什么要乘1000？因为这个时间乘以1000才对，-_-!...
	    cur += readBufDw(loginTime, cur);
	    loginTime *= 1000;

	    // 037-062是未知的26字节
	    // 063-066字节是一个未知服务器1的ip
	    // 067-068字节是一个未知服务器1的端口
	    // 069-072是一个未知服务器2的ip
	    // 073-074是一个未知服务器2的端口
	    // 075-076是两个未知字节
	    // 077-078是两个未知字节
	    cur += 42;

	    // 079-110是client key，这个key用在比如登录QQ家园之类的地方    
	    cur += writeBufData(clientKey, cur, 32);

	    // 111-122是12个未知字节
	    cur += 12;

	    // 123-126是上次登陆的ip
	    cur += readBufDw(lastLogIp, cur);

	    // 127-130是上次登陆的时间
	    cur += readBufDw(lastLoginTime, cur);
	    lastLoginTime *= 1000;

	    // 131-138是8个未知字节
	    // do nothing
	    break;
	case QQ_LOGIN_REPLY_PASSWORD_ERROR:
	    // 密码错误，我们得到服务器发回来的消息
	    replyMessage.assign(reinterpret_cast<const char*>(cur), 
		    reinterpret_cast<const char*>(buf) + len);	
	    //replyMessage.append(1, '\0');
	    break;
	case QQ_LOGIN_REPLY_REDIRECT:
	    // 登陆重定向，可能是为了负载平衡
	    // 001-004字节是用户QQ号
	    cur += 4;

	    // 005-008字节是重定向到的服务器IP
	    cur += readBufDw(redirectIp, cur);

	    // 009-010字节是重定向到的服务器的端口
	    cur += readBufW(redirectPort, cur);

	    break;   
	default:
	    throw runtime_error("LoginReplyPacket parse error");
    }

}

InPacket* LoginReplyPacket::
create(const uint8_t* buf, int len)
{
    return new LoginReplyPacket(buf, len);
}

void LoginReplyPacket::process(QQClient& client)
{
    client.onLogin(*this);
}


//=====================================================================//
int LogoutPacket::putBody(uint8_t* buf) const
{
    return writeBufData(buf, client.getPwkey(), QQ_KEY_LENGTH);
}


int KeepAlivePacket::putBody(uint8_t* buf) const
{
    return sprintf(reinterpret_cast<char*>(buf), "%d", client.getUid());
}

/** 请求一些操作需要的密钥，比如文件中转，视频也有可能 */
int RequestKeyPacket::putBody(uint8_t* buf) const
{
    buf[0] = request;
    return 1;
}
